package net.qiqbframework.common.resolving;


import net.qiqbframework.common.utils.AnnotationUtil;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;

public class AnnotatedResolvedAttributes implements ResolvedAttributes {

    private final AnnotatedElement annotatedElement;

    private final SimpleResolvedAttributes simpleResolvedAttributes;

    public AnnotatedResolvedAttributes(AnnotatedElement annotatedElement) {
        this.annotatedElement = annotatedElement;
        this.simpleResolvedAttributes = new SimpleResolvedAttributes(constructHandlerAttributesFor(annotatedElement));

    }

    private static Map<String, Object> constructHandlerAttributesFor(AnnotatedElement element) {
        final Map<String, Object> attributes = new HashMap<>();
        Set<Class<? extends Annotation>> visitedAnnotations = new HashSet<>();

        for (Annotation annotation : element.getAnnotations()) {
            Set<Class<? extends Annotation>> annotatedWithHasHandlerAttributes = new HashSet<>();
            if (AnnotationUtil.isAnnotatedWith(annotation.annotationType(),
                    ResolveAttributes.class,
                    annotatedWithHasHandlerAttributes,
                    visitedAnnotations)) {
                for (Class<? extends Annotation> handlerAnnotation : annotatedWithHasHandlerAttributes) {
                    AnnotationUtil.findAnnotationAttributes(element, handlerAnnotation, true).ifPresent(
                            annotatedAttributes -> annotatedAttributes.forEach(
                                    (attributeName, attribute) -> attributes.put(
                                            prefixedKey(handlerAnnotation.getSimpleName(), attributeName), attribute
                                    )
                            )
                    );
                }
            }
        }

        return attributes;
    }

    private static String prefixedKey(String handlerType, String attributeName) {
        return handlerType + "." + attributeName;
    }

    @Override
    public <R> R get(String attributeKey) {
        return simpleResolvedAttributes.get(attributeKey);
    }

    @Override
    public Map<String, Object> getAll() {
        return simpleResolvedAttributes.getAll();
    }

    @Override
    public boolean contains(String attributeKey) {
        return simpleResolvedAttributes.contains(attributeKey);
    }

    @Override
    public boolean isEmpty() {
        return simpleResolvedAttributes.isEmpty();
    }

    @Override
    public ResolvedAttributes mergedWith(ResolvedAttributes other) {
        return simpleResolvedAttributes.mergedWith(other);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        AnnotatedResolvedAttributes that = (AnnotatedResolvedAttributes) o;
        return Objects.equals(annotatedElement, that.annotatedElement) && Objects.equals(
                simpleResolvedAttributes,
                that.simpleResolvedAttributes);
    }

    @Override
    public int hashCode() {
        return Objects.hash(annotatedElement, simpleResolvedAttributes);
    }

    @Override
    public String toString() {
        return "AnnotatedHandlerAttributes{" +
                "annotatedElement=" + annotatedElement +
                ", simpleHandlerAttributes=" + simpleResolvedAttributes +
                '}';
    }
}
